home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 076-100 / scopedisk81 / wkeys / wkeys.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  12KB  |  357 lines

  1. /*
  2.  *  wKeys.c    Moves and activates windows and screens via keystrokes.
  3.  *
  4.  *             Copyright (c) 1987,1988 by Davide P. Cervone
  5.  *  You may use this code provided this copyright notice is left intact.
  6.  */
  7.  
  8. #include <exec/types.h>
  9. #include <libraries/dos.h>
  10. #include <exec/io.h>
  11. #include <exec/memory.h>
  12. #include <exec/interrupts.h>
  13. #include <devices/input.h>
  14. #include <devices/inputevent.h>
  15.  
  16. #include "wKeys.h"
  17.  
  18. static char *program  = "wKeys";
  19. static int   version  = 2;
  20. static char *date     = "January 1988";
  21. static char *author   = "Copyright (c) 1987,1988 by Davide P. Cervone";
  22. static int   hversion = 0;
  23.  
  24. static char *PortName = "wKeysPort";
  25. static char *handler  = "L:wKeys-Handler";     /* the handler file */
  26. #define HANDLER            &(handler[2])       /* without the "L:" */
  27.  
  28. /*
  29.  *  This is the structure that holds the handler information between calls
  30.  *  to wKeys.  We create a named, public message-port that points to
  31.  *  an instance of this structure so that we can find this information
  32.  *  when we are asked to remove the handler.  The PortName is stored here 
  33.  *  (NamedPort->mp_Node.ln_Name uses this area for it's name).   The other 
  34.  *  data are what we need in order to remove the handler and clean up properly.
  35.  */
  36.  
  37. struct HandlerBlock
  38. {
  39.    char *PortName;                  /* name of the public, named message-port */
  40.    struct Interrupt Handler;        /* the handler added to the handler chain */
  41.    struct IntuitionBase *Ibase;     /* an error if the handler can't be found */
  42.    struct LayersBase *Lbase;        /* library base used by the handler */
  43.    long Segment;                    /* pointer from LoadSeg() */
  44.    struct HotKey *Keys;             /* pointer to Key array */
  45.    struct MsgPort *ReplyPort;       /* the reply port for CLOSE-WINDOW */
  46.    int KeyCount;                    /* size of Key array */
  47. };
  48. #define HANDLERINFOSIZE     sizeof(struct HandlerBlock)
  49. #define NAMESIZE            (strlen(PortName)+1)
  50.  
  51. /*extern struct MsgPort *CreatePort();*/
  52. extern struct IOStdReq *CreateStdIO();
  53. extern struct MsgPort *FindPort(), *CreatePort();
  54. extern APTR AllocMem();
  55. extern long LoadSeg();
  56.  
  57. #define INTUITION_REV   0L
  58. #define LAYERS_REV      0L
  59.  
  60. struct IntuitionBase  *IntuitionBase = NULL;
  61. struct LayersBase     *LayersBase    = NULL;
  62. extern struct SysBase *SysBase;
  63.  
  64. struct MsgPort *InputPort = NULL;     /* Port used to talk to Input.Device */
  65. struct IOStdReq *InputBlock = NULL;   /* request block used with Input.Device */
  66. LONG InputDevice = 0;                 /* flag whether Input.Device is open */
  67. struct MsgPort *NamedPort = NULL;     /* holds info needed to remove handler */
  68. struct MsgPort *ReplyPort = NULL;     /* reply port for CLOSE-WINDOW */
  69. struct HandlerBlock *HandlerInfo = NULL; /* holds info stored in NamedPort */
  70.  
  71. extern struct HotKeyItem *KeyList;
  72. extern struct HotKey *KeyArray;
  73. extern int KeyCount;
  74. #define KEYARRAYSIZE    (KeyCount*sizeof(struct HotKey))
  75. extern void GetKeyArray();
  76.  
  77. /*
  78.  *  DeleteNonSigPort()
  79.  *
  80.  *  Deletes a message port with signal type PA_IGNORE.  Based on
  81.  *  DeletePort() from the exec support functions documented in the RKM
  82.  */
  83.  
  84. void DeleteNonSigPort(thePort)
  85. struct MsgPort *thePort;
  86. {
  87.    if (thePort->mp_Node.ln_Name) RemPort(thePort);
  88.    thePort->mp_Node.ln_Type = 0xFF;
  89.    thePort->mp_MsgList.lh_Head = (struct Node *) -1;
  90.    FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
  91. }
  92.  
  93. /*
  94.  *  CreateNonSigPort()
  95.  *
  96.  *  Creates a message port with signal type PA_IGNORE.  Based on
  97.  *  CreatePort() from the exec support functions documented in the RKM.
  98.  */
  99.  
  100. struct MsgPort *CreateNonSigPort(name,pri)
  101. char *name;
  102. BYTE pri;
  103. {
  104.    struct MsgPort *thePort;
  105.    
  106.    thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
  107.                                          MEMF_PUBLIC | MEMF_CLEAR);
  108.    if (thePort)
  109.    {
  110.       thePort->mp_Node.ln_Name = name;
  111.       thePort->mp_Node.ln_Pri  = pri;
  112.       thePort->mp_Node.ln_Type = NT_MSGPORT;
  113.       
  114.       thePort->mp_Flags = PA_IGNORE;
  115.       thePort->mp_SigBit = 0;
  116.       thePort->mp_SigTask = NULL;
  117.       
  118.       if (name)
  119.          AddPort(thePort);
  120.         else
  121.          NewList(&(thePort->mp_MsgList));
  122.    }
  123.    return(thePort);
  124. }
  125.  
  126. /*
  127.  *  DoExit()
  128.  *
  129.  *  General purpose exit routine.  If 's' is not NULL, then print an
  130.  *  error message with up to three parameters.  Free any memory, close
  131.  *  any open device, delete any ports, close any libraries, etc.
  132.  */
  133.  
  134. void DoExit(s,x1,x2,x3)
  135. char *s, *x1, *x2, *x3;
  136. {
  137.    long status = RETURN_OK;
  138.    struct HotKeyItem *TempKey;
  139.    
  140.    if (s != NULL)
  141.    {
  142.       printf(s,x1,x2,x3);
  143.       printf("\n");
  144.       status = RETURN_ERROR;
  145.    }
  146.    if (InputDevice)   CloseDevice(InputBlock);
  147.    if (InputBlock)    DeleteStdIO(InputBlock);
  148.    if (InputPort)     DeletePort(InputPort);
  149.    if (NamedPort)     DeleteNonSigPort(NamedPort);
  150.    if (ReplyPort)     DeleteNonSigPort(ReplyPort);
  151.    if (HandlerInfo)
  152.    {
  153.       if (HandlerInfo->PortName) FreeMem(HandlerInfo->PortName,NAMESIZE);
  154.       FreeMem(HandlerInfo,HANDLERINFOSIZE);
  155.    }
  156.    if (KeyArray)      FreeMem(KeyArray,KEYARRAYSIZE);
  157.    while (KeyList)
  158.    {
  159.       TempKey = KeyList;
  160.       KeyList = KeyList->Next;
  161.       FreeMem(TempKey,sizeof(*TempKey));
  162.    }
  163.    if (IntuitionBase) CloseLibrary(IntuitionBase);
  164.    if (LayersBase)    CloseLibrary(LayersBase);
  165.    exit(status);
  166. }
  167.  
  168. /*
  169.  *  CheckLibOpen()
  170.  *
  171.  *  General library open routine.  It opens a library and sets a pointer
  172.  *  to it.  It checks that the library was openned successfully.
  173.  */
  174.  
  175. static void CheckLibOpen(lib,name,rev)
  176. APTR *lib;
  177. char *name;
  178. int rev;
  179. {
  180.    extern APTR OpenLibrary();
  181.  
  182.    if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
  183.       DoExit("Can't open '%s'\n",name);
  184. }
  185.  
  186. /*
  187.  *  Macros that make memory allocation easier.
  188.  */
  189. #define NEW(s,var)      (var = (struct s *)New("var",sizeof(struct s)))
  190. #define NEWCHAR(var,s)  (var = (char *)New("var",s))
  191.  
  192. /*
  193.  *  New()
  194.  *
  195.  *  Allocate public memory of a given size and set it to all zeros.  If there
  196.  *  is not enough memory, then exit with an error, otherwise return the
  197.  *  pointer to the newly allocated memory.
  198.  */
  199.  
  200. APTR New(name,size)
  201. char *name;
  202. int size;
  203. {
  204.    APTR ptr;
  205.    
  206.    if ((ptr = AllocMem(size,MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  207.       DoExit("Can't Get Memory for '%s'",name);
  208.    return(ptr);
  209. }
  210.  
  211. /*
  212.  *  TellInputDevice()
  213.  *
  214.  *  Create a port and I/O block, and open the input device.  Set up the
  215.  *  I/O block to add or remove the input handler, and send the request
  216.  *  to the input device.  Finally, close the device and delete the
  217.  *  I/O block and port.
  218.  */
  219.  
  220. static void TellInputDevice(function)
  221. int function;
  222. {
  223.    long status;
  224.  
  225.    if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
  226.    if ((InputBlock = CreateStdIO(InputPort)) == NULL)
  227.       DoExit("Can't Create Standard IO Block");
  228.    InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
  229.    if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
  230.    
  231.    InputBlock->io_Command = (long) function;
  232.    InputBlock->io_Data    = (APTR) &(HandlerInfo->Handler);
  233.    if (status = DoIO(InputBlock)) DoExit("Error from DoIO:  %ld",status);
  234.  
  235.    CloseDevice(InputBlock);
  236.    DeleteStdIO(InputBlock);
  237.    DeletePort(InputPort);
  238. }
  239.  
  240. /*
  241.  *  CreateHandler()
  242.  *
  243.  *  Open the libraries needed by the input handler and store their locations
  244.  *  in the HandlerInfo structure (so we can close them later).  Try to 
  245.  *  LoadSeg() the handler.  If it is not in the current directory, try the
  246.  *  L: directory.  Exit with an error if the handler can't be found.
  247.  *  Convert the segment pointer into a pointer to the Setup() routine (the
  248.  *  first routine in the handler executable).  Call Setup() and pass it
  249.  *  the pointers to the libraries that it will need to use.  Setup() returns
  250.  *  a pointer to the actual handler routine that should be added into the
  251.  *  input handler chain.  Store this in the HandlerInfo structure so we
  252.  *  can use it to remove the handler later.  Set the handler priority to
  253.  *  51 so that it is ahead of Intuition.
  254.  *
  255.  *  Finally, add the handler in the chain and tell the user that the
  256.  *  handler has been installed.
  257.  */
  258.  
  259. static void CreateHandler()
  260. {
  261.    long (*Setup)();
  262.  
  263.    CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
  264.    CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
  265.    
  266.    HandlerInfo->Ibase = IntuitionBase;
  267.    HandlerInfo->Lbase = LayersBase;
  268.    if ((HandlerInfo->Segment = LoadSeg(HANDLER)) == NULL)
  269.       if ((HandlerInfo->Segment = LoadSeg(handler)) == NULL)
  270.          DoExit("Can't Load '%s'",handler);
  271.    Setup = (long (*)()) ((HandlerInfo->Segment << 2) + 4);
  272.    HandlerInfo->Handler.is_Code = 
  273.       (void (*)()) ((*Setup)(IntuitionBase,LayersBase,SysBase,
  274.                              KeyArray,KeyCount,ReplyPort,&hversion));
  275.    HandlerInfo->Handler.is_Node.ln_Pri = 51;
  276.    HandlerInfo->Keys = KeyArray;
  277.    HandlerInfo->KeyCount = KeyCount;
  278.    HandlerInfo->ReplyPort = ReplyPort;
  279.  
  280.    TellInputDevice(IND_ADDHANDLER);
  281.    printf("%s v%d.%d (%s) Installed\n",program,version,hversion,date);
  282. }
  283.  
  284. /*
  285.  *  Delete Handler()
  286.  *
  287.  *  Retreive the library pointers from the HandlerInfo structure, where
  288.  *  we stored them when we originally installed the handler, then remove
  289.  *  the handler from the input handler chain.  Tell the user that the
  290.  *  handler is gone, and then close the libraries that are no longer needed.
  291.  */
  292.  
  293. static void DeleteHandler()
  294. {
  295.    IntuitionBase = HandlerInfo->Ibase;
  296.    LayersBase    = HandlerInfo->Lbase;
  297.    KeyArray      = HandlerInfo->Keys;
  298.    KeyCount      = HandlerInfo->KeyCount;
  299.    ReplyPort     = HandlerInfo->ReplyPort;
  300.  
  301.    TellInputDevice(IND_REMHANDLER);
  302.    UnLoadSeg(HandlerInfo->Segment);
  303.    printf("%s Removed\n",program);
  304.    
  305.    FreeMem(KeyArray,KEYARRAYSIZE);
  306.    CloseLibrary(IntuitionBase);
  307.    CloseLibrary(LayersBase);
  308. }
  309.  
  310. /*
  311.  *  main()
  312.  *
  313.  *  Check if a message port with our name already exists.
  314.  *  If not, then the handler is not already installed, so:
  315.  *    Allocate a new HandlerInfo structure and initialize the port name.
  316.  *    Create a public, named message-port (we will look for this the next
  317.  *      time wKeys is called).
  318.  *    Make the message port point to the HandlerInfo structure so we
  319.  *      can use it later when the user asks us to remove the handler.
  320.  *      Note that the port is not actually used for putting and getting
  321.  *      messages, so the Task field is never used, so we can take it for
  322.  *      our own uses.
  323.  *    Get a port to use as a reply port for CLOSE-WINDOW intuimessages.
  324.  *    Finally, add the input handler into the chain.
  325.  *  Otherwise, the port exists, so wKeys already is installed:
  326.  *    Retreive the HandlerInfo poiner from the port, and remove the 
  327.  *      handler from the input handler chain.
  328.  *    Free the memory used by the HandlerInfo, and delete the message ports.
  329.  */
  330.  
  331. void main(argc,argv)
  332. int argc;
  333. char **argv;
  334. {
  335.    NamedPort = FindPort(PortName);
  336.    if (NamedPort == NULL)
  337.    {
  338.       NEW(HandlerBlock,HandlerInfo);
  339.       NEWCHAR(HandlerInfo->PortName,NAMESIZE);
  340.       strcpy(HandlerInfo->PortName,PortName);
  341.       if ((NamedPort = CreateNonSigPort(HandlerInfo->PortName,0)) == NULL)
  342.          DoExit("Can't Create Message Port '%s'",PortName);
  343.       if ((ReplyPort = CreateNonSigPort(NULL,0)) == NULL)
  344.          DoExit("Can't Create Reply Port");
  345.       NamedPort->mp_SigTask = (struct Task *)HandlerInfo;
  346.       GetKeyArray(argc,argv);
  347.       CreateHandler();
  348.    } else {
  349.       HandlerInfo = (struct HandlerBlock *)(NamedPort->mp_SigTask);
  350.       DeleteHandler();
  351.       FreeMem(HandlerInfo->PortName,NAMESIZE);
  352.       FreeMem(HandlerInfo,HANDLERINFOSIZE);
  353.       DeleteNonSigPort(ReplyPort);
  354.       DeleteNonSigPort(NamedPort);
  355.    }
  356. }
  357.